home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 22 code / Futures / FutureShock / Main.cp < prev    next >
Encoding:
Text File  |  1995-07-27  |  10.9 KB  |  390 lines  |  [TEXT/MMCC]

  1. /*================================================================================
  2.     FutureShock
  3.     
  4.     ©1994 Greg Anderson
  5.     greggor@apple.com
  6.     
  7.     A program that uses the Futures package
  8. ================================================================================*/
  9. #include <GestaltEqu.h>
  10. #include <Palettes.h>
  11.  
  12. #include "Main.h"
  13. #include "FutureShockDialog.h"
  14. #include "AppleEventHandlers.h"
  15.  
  16. #include "MenuHandler.h"
  17. #include "EventHandler.h"
  18.  
  19. #include "MacUtilities.h"
  20. #include "DialogUtilities.h"
  21. #include "AppleEventUtilities.h"
  22. #include "Exceptions.h"
  23. #include "Futures.h"
  24. #include <AEObjects.h>
  25.  
  26. //
  27. // Prototypes for private functions:
  28. //
  29. void                    InitAll(void);
  30. pascal OSErr            QuitApplicationEvent(TAEvent& ae, TAEvent& reply, long refCon);
  31. pascal OSErr            ThreadCreateHandler(ThreadEntryProcPtr threadEntry, void *threadParam, long handlerRefCon, ThreadID *threadMade);
  32.  
  33. //
  34. // Globals defined in this file:
  35. //
  36. Rect                    gUniverseRect;
  37. RgnHandle                gUniverseRgn = nil;
  38. RgnHandle                gScratchRgn = nil;
  39. GrafPtr                    gWindowMgrPort = nil;
  40.  
  41. SysEnvRec                gThisMacintosh;
  42. Boolean                    gHasAppleEvents;
  43. Boolean                    gApplicationShouldQuit = false;
  44.  
  45. #if USESROUTINEDESCRIPTORS
  46.     static RoutineDescriptor gQuitApplicationHandlerRD    = BUILD_ROUTINE_DESCRIPTOR(uppAEEventHandlerProcInfo, QuitApplicationEvent);
  47. #endif
  48.  
  49. Boolean gHasIdleUpdate = false;
  50. Str255 gAppName;
  51.  
  52.  
  53. //----------------------------------------------------------------------------------------
  54. // main: 
  55. //----------------------------------------------------------------------------------------
  56. void main()
  57. {
  58.     RgnHandle        mouseRegion;
  59.     AppFile            theFile;
  60.     DialogPtr        splash;
  61.     short            preLoadFiles;
  62.     short            message;
  63.     short            i;
  64.     OSErr            err = noErr;
  65.     
  66.     //
  67.     // Initialize all of the ToolBox managers, change the cursor
  68.     // shape to a watch and display the splash screen.
  69.     //
  70.     InitAll();
  71.     ChangeCursor( watchCursor );
  72.     SetupMenuBar(1001, 1002);
  73.     
  74.     /*
  75.     // Schlep together our command table
  76.     //
  77.     // (command ID, menu ID, item #)
  78.     */
  79.     AddItemIDtoTable( 1, 2, 3 );
  80.     AddItemIDtoTable( 2, 2, 1 );
  81.     
  82.     //
  83.     // Before any threads are created, make sure that the main thread
  84.     // gets swap in and swap out context switch messages
  85.     //
  86.     ThreadCreateNotifyHandler(kApplicationThreadID, 0);
  87.     
  88.     //
  89.     // Call InitFutures declaring that we would like the
  90.     // Futures package to make a thread for IdleFutures,
  91.     // and that it should create a new thread every time
  92.     // AEProcessAppleEvent dispatches an event.  Also,
  93.     // give InitFutures a UPP to our thread create notify
  94.     // handler.
  95.     //
  96.     // Every high-level-event-aware application needs a
  97.     // quit-application handler; otherwise, it won't quit
  98.     // when the machine is shut down (for example)
  99.     //
  100. #if USESROUTINEDESCRIPTORS
  101.     AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, &gQuitApplicationHandlerRD, 0, false);
  102. #else
  103.     AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, (AEEventHandlerProcPtr) &QuitApplicationEvent, 0, false);
  104. #endif
  105.     InitFutures(ThreadCreateHandler);
  106.     
  107.     InstallAppleEventHandlers();
  108.     AEObjectInit();
  109.  
  110.     //
  111.     // Ask the process manager what our name is
  112.     //
  113.     ProcessInfoRec theProc;
  114.     ProcessSerialNumber myPSN;
  115.     GetCurrentProcess(&myPSN);
  116.     theProc.processInfoLength = sizeof(ProcessInfoRec);
  117.     theProc.processName = gAppName;
  118.     theProc.processAppSpec = nil;
  119.     theProc.processLocation = nil;
  120.     FailErr(GetProcessInformation(&myPSN, &theProc));    
  121.     
  122.     //
  123.     // Set the cursor back to an arrow
  124.     //
  125.     InitCursor();
  126.     
  127.     //
  128.     // Set up the initial mouse region
  129.     //
  130.     mouseRegion = NewRgn();
  131.     
  132.     long powerMgrResult;
  133.     if((Gestalt(gestaltPowerMgrAttr, &powerMgrResult) == noErr) && ((powerMgrResult & (1 << gestaltPMgrCPUIdle)) != 0))
  134.         gHasIdleUpdate = true;
  135.  
  136.     //
  137.     // Set up a failure handler for failures that are not
  138.     // trapped elsewhere
  139.     //
  140.     Try
  141.     {
  142.         //
  143.         // When the program begins, open our dialog box.
  144.         // If the dialog is ever closed, we will quit (DA model)
  145.         //
  146.         OpenFutureShockDialog();
  147.         
  148.         //
  149.         // Live here until the 'gApplicationShouldQuit' flag
  150.         // becomes true
  151.         //
  152.         while(gApplicationShouldQuit == false)
  153.             HandleEvents(mouseRegion);
  154.     }
  155.     Catch(err)
  156.     {
  157.         //
  158.         // We don't expect to ever get here...
  159.         //
  160.     }
  161.     
  162.     // DebugStr("\pAbout to quit!");
  163. } // main 
  164.  
  165. //----------------------------------------------------------------------------------------
  166. // InitAll: 
  167. // 
  168. // Initialize various Macintosh managers
  169. //----------------------------------------------------------------------------------------
  170. void InitAll()
  171. {
  172.     OSErr    theErr;
  173.     long    heapSpace;
  174.     Ptr        appLimit;
  175.     THz        appBase;
  176.     long    gestaltResult;
  177.     short    callsToMoreMasters = 10;
  178.     
  179.     appBase = ApplicZone();
  180.     appLimit = GetApplLimit();
  181.     heapSpace = FreeMem();
  182.     MaxApplZone();
  183.     appLimit = GetApplLimit();
  184.     heapSpace = FreeMem();
  185.     while( callsToMoreMasters-- )
  186.         MoreMasters();
  187.     
  188.     InitGraf(&qd.thePort);
  189.     InitFonts();
  190.     FlushEvents(everyEvent, 0);
  191.     InitWindows();
  192.     InitMenus();
  193.     TEInit();
  194.     InitDialogs(0L);
  195.     
  196.     //
  197.     // Get the SysEnvirons record
  198.     //
  199.     SysEnvirons( 1, &gThisMacintosh );
  200.  
  201.     //
  202.     // Check to see if AppleEvents are available
  203.     //
  204.     theErr = Gestalt( gestaltAppleEventsAttr, &gestaltResult );
  205.     gHasAppleEvents = ( (theErr == noErr) && ((gestaltResult & (1L << gestaltAppleEventsPresent)) != 0) );
  206.     
  207.     //
  208.     // Set a global rectangle to hold the extent of QuickDraw workspace
  209.     // (Note:  QuickDraw coordinates range from +-32767, but there
  210.     //  are bugs in QuickDraw that make it inadvisable to go beyond
  211.     //  +-16000 or so.)
  212.     //
  213.     SetRect(&gUniverseRect,-16000,-16000,16000,16000);
  214.     gUniverseRgn = NewRgn();
  215.     RectRgn(gUniverseRgn, &gUniverseRect);
  216.     gScratchRgn = NewRgn();
  217.     GetPort(&gWindowMgrPort);
  218. } // InitAll 
  219.  
  220. //----------------------------------------------------------------------------------------
  221. // ExitProgram: 
  222. //----------------------------------------------------------------------------------------
  223. OSErr ExitProgram(CWindowPtr window, short item)
  224. {
  225.     //
  226.     // A "real" program would try to close all of its windows
  227.     // first (give the user a chance to cancel)
  228.     //
  229.     gApplicationShouldQuit = true;
  230.     
  231.     return noErr;
  232. } // ExitProgram 
  233.  
  234. //----------------------------------------------------------------------------------------
  235. // QuitApplicationEvent: 
  236. //----------------------------------------------------------------------------------------
  237. pascal OSErr QuitApplicationEvent(TAEvent& ae, TAEvent& reply, long refCon)
  238. {
  239.     //
  240.     // You should never call ExitToShell from an AppleEvent handler
  241.     //
  242.     gApplicationShouldQuit = true;
  243.     
  244.     return noErr;
  245. }
  246.  
  247. extern TException* gExceptionStack;
  248.  
  249. #if __MWERKS__
  250. extern void* __local_destructor_chain;
  251. #endif
  252.  
  253. class TThreadContext
  254. {
  255. public:
  256.                     TThreadContext(long threadCreateRefcon) :
  257. #if __MWERKS__
  258.                     fLocalDestructorChain(nil),
  259. #endif
  260.                     fThreadCreateRefcon(threadCreateRefcon),
  261.                     fExceptionStack(nil)
  262.                     {};
  263.     
  264.     void            SwapIn(ThreadID);
  265.     void            SwapOut(ThreadID);
  266.     void            DisposeContext(ThreadID);
  267.  
  268.     long            ThreadCreateRefcon() const { return fThreadCreateRefcon; }
  269.     
  270. private:
  271.  
  272. #if __MWERKS__
  273.     void*            fLocalDestructorChain;
  274. #endif
  275.     const long        fThreadCreateRefcon;
  276.     TException*        fExceptionStack;
  277. };
  278.  
  279. //----------------------------------------------------------------------------------------
  280. // TThreadContext::SwapIn
  281. //----------------------------------------------------------------------------------------
  282. void TThreadContext::SwapIn(ThreadID threadID)
  283. {
  284.     gExceptionStack = fExceptionStack;
  285. #if __MWERKS__
  286.     __local_destructor_chain = fLocalDestructorChain;
  287. #endif
  288. }
  289.  
  290. //----------------------------------------------------------------------------------------
  291. // TThreadContext::SwapOut
  292. //----------------------------------------------------------------------------------------
  293. void TThreadContext::SwapOut(ThreadID threadID)
  294. {
  295.     fExceptionStack = gExceptionStack;
  296. #if __MWERKS__
  297.     fLocalDestructorChain = __local_destructor_chain;
  298. #endif
  299. }
  300.  
  301. //----------------------------------------------------------------------------------------
  302. // TThreadContext::DisposeContext
  303. //----------------------------------------------------------------------------------------
  304. void TThreadContext::DisposeContext(ThreadID threadID)
  305. {
  306.     delete this;
  307. }
  308.  
  309. //----------------------------------------------------------------------------------------
  310. // SwapThreadContextIn
  311. //----------------------------------------------------------------------------------------
  312. pascal void SwapThreadContextIn(ThreadID thread, void* refCon)
  313. {
  314.     TThreadContext* threadContext = (TThreadContext*) refCon;
  315.     threadContext->SwapIn(thread);
  316. }
  317.  
  318. //----------------------------------------------------------------------------------------
  319. // SwapThreadContextOut
  320. //----------------------------------------------------------------------------------------
  321. pascal void SwapThreadContextOut(ThreadID thread, void* refCon)
  322. {
  323.     TThreadContext* threadContext = (TThreadContext*) refCon;
  324.     threadContext->SwapOut(thread);
  325. }
  326.  
  327. //----------------------------------------------------------------------------------------
  328. // DestroyThreadContext
  329. //----------------------------------------------------------------------------------------
  330. pascal void DestroyThreadContext(ThreadID thread, void* refCon)
  331. {
  332.     TThreadContext* threadContext = (TThreadContext*) refCon;
  333.     threadContext->DisposeContext(thread);
  334. }
  335.  
  336. //----------------------------------------------------------------------------------------
  337. // ThreadCreateNotifyHandler
  338. //----------------------------------------------------------------------------------------
  339. pascal OSErr ThreadCreateNotifyHandler(ThreadID createdThread, long threadCreateRefcon)
  340. {
  341.     TThreadContext* threadContext = new TThreadContext(threadCreateRefcon);
  342.     
  343.     SetThreadSwitcher(createdThread, SwapThreadContextIn, (void*) threadContext, true);
  344.     SetThreadSwitcher(createdThread, SwapThreadContextOut, (void*) threadContext, false);
  345.     SetThreadTerminator(createdThread, DestroyThreadContext, (void*) threadContext);
  346.     
  347.     return noErr;
  348. }
  349.  
  350. //----------------------------------------------------------------------------------------
  351. // NewThreadWithNotification
  352. //
  353. // This routine calls 'NewThread', then notifies the application of what it has done
  354. //----------------------------------------------------------------------------------------
  355. OSErr NewThreadWithNotification(ThreadStyle threadStyle, ThreadEntryProcPtr threadEntry, void *threadParam, Size stackSize, ThreadOptions options, void **threadResult, ThreadID *threadMade, long threadCreateRefcon)
  356. {
  357.     OSErr err = noErr;
  358.     
  359.     err = NewThread(threadStyle, threadEntry, threadParam, stackSize, options, threadResult, threadMade);
  360.     if(err == noErr)
  361.         err = ThreadCreateNotifyHandler(*threadMade, threadCreateRefcon);
  362.     
  363.     return err;
  364. }
  365.  
  366. //----------------------------------------------------------------------------------------
  367. // ThreadCreateHandler
  368. //----------------------------------------------------------------------------------------
  369. pascal OSErr ThreadCreateHandler(ThreadEntryProcPtr threadEntry, void *threadParam, long handlerRefCon, ThreadID *threadMade)
  370. {
  371.     Size stackSize = 0;
  372.     ThreadOptions options = kCreateIfNeeded | kFPUNotNeeded;
  373.     
  374.     OSErr theErr = NewThread(
  375.         kCooperativeThread,
  376.         threadEntry,
  377.         threadParam,
  378.         stackSize,
  379.         options,
  380.         nil,
  381.         threadMade);
  382.     
  383.     if(theErr == noErr)
  384.         theErr = ThreadCreateNotifyHandler(*threadMade, handlerRefCon);
  385.  
  386.     return theErr;
  387. }
  388.  
  389.  
  390.